package ru.hei.pointsserver.repository

import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.PostgreSQLContainer
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import org.testcontainers.utility.DockerImageName
import java.time.Duration
import java.time.temporal.ChronoUnit


@Testcontainers
@DataR2dbcTest
open class BaseRepositoryTest {

  companion object {
    @Container
    private val postgres: PostgreSQLContainer<*> = PostgreSQLContainer(DockerImageName.parse("postgres:16.3"))
      .apply {
        this
          .withDatabaseName("test")
          .withUsername("test")
          .withPassword("test")
      }

    @JvmStatic
    @DynamicPropertySource
    fun properties(registry: DynamicPropertyRegistry) {
      registry.add("spring.r2dbc.url", Companion::r2dbcUrl)
      registry.add("spring.r2dbc.username", postgres::getUsername)
      registry.add("spring.r2dbc.password", postgres::getPassword)

      registry.add("spring.liquibase.url", Companion::jdbcUrl)
      registry.add("spring.liquibase.user", postgres::getUsername)
      registry.add("spring.liquibase.password", postgres::getPassword)
    }

    fun r2dbcUrl(): String {
      return "r2dbc:${postgresUrl()}"
    }

    fun jdbcUrl(): String {
      return "jdbc:${postgresUrl()}"
    }

    private fun postgresUrl() =
      "postgresql://${postgres.host}:${postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT)}/${postgres.databaseName}"

    @JvmStatic
    @BeforeAll
    internal fun setUp() {
      postgres.waitingFor(
        LogMessageWaitStrategy()
          .withRegEx(".*database system is ready to accept connections.*\\s")
          .withTimes(1)
          .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS))
      )
        .start()
    }

    @JvmStatic
    @AfterAll
    internal fun tearDown() {
      postgres.stop()
    }
  }
}
